import {
  MATCH_CASE_STRING,
  MdcCase,
  processCaseString
} from './processCaseString';
import {
  MATCH_TABLE_STRING,
  MdcTable,
  processTableString
} from './processTableString';

type MdcBlock = string | MdcCase | MdcTable

const processorList = [] as {
  regexp: RegExp,
  processor: (str: string, processCountIndex: number) => MdcBlock,
}[]

/**
 * 注册解析器
 * @param regexp
 * @param processor
 */
export function registryProcessor(regexp: RegExp, processor: (str: string) => MdcBlock) {
  processorList.push({regexp, processor})
}

registryProcessor(MATCH_TABLE_STRING, processTableString)
registryProcessor(MATCH_CASE_STRING, processCaseString)

export function processMdc(content: string | undefined):MdcBlock[] {
  if(!content) return [];

  const processorMatchString = processorList.reduce((ret, item, processorIndex) => {
    const {regexp} = item; //const MATCH_CASE_STRING = /:::case((?:.|\s)*?):::/g
    const stringList = [] as string[];
    content = content!.replace(regexp, (...args) => {
      stringList.push(args[1].trim()); //即一个 :::case((?:.|\s)*?):::
      return `:::separator::: process_${processorIndex} :::separator:::`; //`:::separator::: process_0 :::separator:::`
    });
    ret.push(stringList); //一个stringList代表这篇md里所有的case或则table
    return ret;
  },[] as string[][]);
  // 经过上面的处理, 所有的case和table都被分进了自己的数组里, 并且case组和table组都被放进了 processorMatchString这个二维数组
  // 而传进来的源 --- content, 其中被匹配上的"块"都被替换为了 `:::separator::: process_${processorIndex} :::separator:::` 作为占位

  const processorCountIndex = [] as number[];
  const ret = content.split(`:::separator:::`)
    .map(str => str.trim())
    .reduce((ret, item) => {
      const match = item.match(/process_(.*)/);
      if(!!match){
        const processorIndex = Number(match[1]);

        //主要是为了计算 我们正在处理的'块'是组里的第几个 这样才好从processorMatchString里拿取实际的内容
        if (processorCountIndex[processorIndex] == null) {
          processorCountIndex[processorIndex] = 0;
        }
        const pci = (processorCountIndex[processorIndex])++; // const x = (expr)++ ---> 会先赋值再++
        //processorMatchString[processorIndex]      ---> 拿到组, 是case组 还是 table组？
        //processorMatchString[processorIndex][pci] ---> 拿到组里的第几项 (一篇md可能有多个case, 取第几个case) 给对应的processor去处理
        ret.push(processorList[processorIndex].processor(processorMatchString[processorIndex][pci], pci)); //拿到对应处理器转换后的内容 --- 是个对象
      }else {
        !!item && ret.push(item); //不需要我们进行额外处理的markdown内容 (即非case或table)
      }

      return ret;
    },[] as MdcBlock[]);

  return ret
}
